package project5;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.HashSet;

public class DTI
{
	private static String STOP_FILE_OPTION ="-s";
	private static String BREAK_FILE_OPTION ="-b";
	private static String stopFilePath;
	private static String breakChars;
	private static List<String> _filenames;

	private static HashSet<String> indexWords = new HashSet<String>();
	private static ArrayList<FreqRepresenter> freakyIndexer
		= new ArrayList<FreqRepresenter>();


	public static void main(String[] args)
	{
		_filenames = new ArrayList<String>();
		
		try
		{
			parseArguments(args);
		}
		catch (ProjectException pe)
		{
			ErrorUtility.handleError(pe);
			System.exit(255);
		}

		//here i am writing a function to read the contents of the entire corpus and create word out of it
		//and save it in an array :)
		corpusReader();
	}
	public static void corpusReader()
	{
		// Recursively read all files in the directories if it there are any.
		List<File> files = null;
		
		try
		{
			files = expoundFiles(_filenames);
		}
		catch (ProjectException pe)
		{
			ErrorUtility.handleError(pe);
			System.exit(255);
		}
		
		// Get stop words.
		StopWordProcessor processor = new StopWordProcessor();
		ArrayList<String> stopWords = processor.createStopWordArrayList(stopFilePath);
		
		//now that i have all the file paths available for the corpus :)
		//i can create documents
		ArrayList<Document> DocumentArray  = new ArrayList<Document>();
		Iterator<File> fileIter2 = files.iterator();
		String fileBeingRead = new String ("");
		long fileNumber=0;

		while (fileIter2.hasNext())
		{
			fileNumber++;
			fileBeingRead = fileIter2.next().toString();		
			Document d = new Document();
			d.fileName=fileBeingRead;
			WordCounter wc = new WordCounter();
			wc.addBreakCharacters(breakChars);
			
			try
			{
				d.wordsWithoutStopWords  = wc.WordCreator(fileBeingRead);
			}
			catch (ProjectException pe)
			{
				ErrorUtility.handleError(pe);
			}
			
			d.wordsWithoutStopWords.removeAll(stopWords);
			
			DocumentArray.add(d);
		}
		
		//now after creating docs-stop words
		//run the histogram program
		for (Document d : DocumentArray)
		{
			//indexWords.addAll(HistogramProcessor.Histo(
			//		d.wordsWithoutStopWords, DocumentArray.size()));
			indexWords.addAll(d.wordsWithoutStopWords);
		}
		
		for (String word : indexWords)
		{
			System.out.println(word);
		}

		//now the next step as the complete corpus has been indexed...
		//we can now look at the index creation 
		System.out.println("All ready to create the bit vector :)");
		FreqRepresenter fr = new FreqRepresenter();
		DocumentIndexer di = new DocumentIndexer(new ArrayList<String>(indexWords));
		
		long totWords=0;
		
		for (Document doc : DocumentArray)
		{
			fr = di.bitVectorCreator(doc.fileName, doc.wordsWithoutStopWords);
			freakyIndexer.add(fr);
			totWords += doc.wordsWithoutStopWords.size();
		}
		
		System.out.println("Done!");

		//bingoo time to write to this to the index...DEFAULT CORPUS PATH
		Index i = new Index();

		i.noOfFilesInCorpus=DocumentArray.size();
		i.noOfWordsInCorpus = totWords;
		i.noOfCharacters= WordCounter._bytesRead;

		i.indexFileName = "DTI.out";
		i.dateTimeofCreation = System.currentTimeMillis();
		i.directoryOfIndexFile = new File(".").getAbsolutePath();
		File f = new File("DTI.out");	
		i.indexSizeInBytes = f.length();

		i.indexWords = new ArrayList<String>(indexWords);
		i.freqIndexer = freakyIndexer;

		//now write to the index file dear...good luck :)
		String position = "DTI.out";
		FileOutputStream fout = null;
		
		try
		{
			fout = new FileOutputStream(position); 
			ObjectOutputStream s = new ObjectOutputStream(fout); 
			s.writeObject(i); 
			s.flush();

		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		} 
		finally
		{
			if (null != fout)
			{
				try
				{
					fout.close();
				}
				catch (IOException ioe)
				{
					//Ignore
				}
			}
		}
	}
	
	private static void parseArguments(String[] args) throws ProjectException
	{
		String argument;
		boolean stopWordsSet = false;
		boolean breakCharsSet = false;
		boolean fileNamesSet = false;
		
		for (int i = 0; i < args.length; i++)
		{
			argument = args[i];
			
			if (STOP_FILE_OPTION.equals(argument))
			{
				if ((null != stopFilePath) || stopWordsSet)
				{
					throw new ProjectException("Duplicate stop word file option");
				}
				
				if (fileNamesSet)
				{
					throw new ProjectException("Stop word option must come "
							+ "before the names of files to be indexed.");
				}
				
				//Next argument is being used already, so skip parsing it.
				i += 1;
				stopFilePath = args[i];
				stopWordsSet = true;
			}
			else if (BREAK_FILE_OPTION.equals(argument))
			{
				if ((null != breakChars) || breakCharsSet)
				{
					throw new ProjectException("Duplicate break character option");
				}
				
				if (fileNamesSet)
				{
					throw new ProjectException("Break characters must come "
							+ "before the names of files to be indexed.");
				}
				
				//Next argument is being used already, so skip parsing it.
				i += 1;
				breakChars = args[i];
				breakCharsSet = true;
			}
			else
			{
				_filenames.add(args[i]);
				fileNamesSet = true;
			}
		}
		
		if (_filenames.isEmpty())
		{
			throw new ProjectException(ErrorUtility.NO_CORPUS_SPECIFIED);
		}
	}
	
	private static List<File> expoundFiles(List<String> filenames) throws ProjectException
	{
		//Dealing with the raw file names here.
		List<File> returnFiles = new ArrayList<File>();
		
		for (String filename: filenames)
		{
			File f = new File(filename);
			if (!f.exists())
			{
				throw new ProjectException(ErrorUtility.CANNOT_FIND_FILE); 
			}
			
			if (f.isDirectory())
			{
				returnFiles.addAll(getFiles(f));
			}
			else
			{
				returnFiles.add(f);
			}
		}
		
		return returnFiles;
	}
	
	private static List<File> getFiles(File directory) throws ProjectException
	{
		if (!directory.exists())
		{
			throw new ProjectException(ErrorUtility.CANNOT_FIND_FILE);
		}
		
		List<File> returnFiles = new ArrayList<File>();
		File[] currentFiles = directory.listFiles();
		
		for (File f : currentFiles)
		{
			if (f.isDirectory())
			{
				returnFiles.addAll(getFiles(f));
			}
			else
			{
				returnFiles.add(f);
			}
		}
		
		return returnFiles;
	}
}
